home *** CD-ROM | disk | FTP | other *** search
/ The Arsenal Files 3 / The Arsenal Files 3.iso / gen_prog / appdemo.exe / STRING.APP < prev    next >
Text File  |  1994-11-07  |  28KB  |  955 lines

  1. //                            STRING LIBRARY
  2. //                            ==============
  3.  
  4. // This file contains the STRING library of functions.
  5. // You can modify it to suit your particular needs.  If you
  6. // do then it would be a good idea to lable all your changes with a unique
  7. // string in a comment so that if you get an upgrade you can remake those
  8. // changes.
  9.  
  10.  
  11. // MAXSTRUCTURES is the maximum number of structures with strings in them
  12. // that can be current at any one time.  It is used by TidyStringHeap()
  13. // to do a garbage collection when the string heap gets full.
  14. #define MAXSTRUCTURES 100
  15.  
  16.  
  17. string MidString(BX_String, CX_Start, int Length)
  18. {
  19.  // Returns Length characters of BX_String starting from CX_Start
  20.  string Dest;
  21.  
  22.  PUSH CX;                    // Save CX for later
  23.  Dest = BX;                  // Copy to new string
  24.  POP CX;                     // Restore CX again
  25.  while(CX_Start > 0)         // For each character before CX_Start
  26.  {
  27.   if(Dest[0] == 0) break;    // Stay within bounds of string
  28.   Dest[0] = 0;               // Clear the first character in Dest
  29.   Dest++;                    // Move the Dest pointer forward
  30.   CX--;                      // One less character to delete
  31.  }
  32.  BX = Dest;                  // Point to start of string
  33.  CX = BX + Length;           // Pointer from where to start deleting
  34.  while(S1[BX])               // while not end of string
  35.  {
  36.   if(BX .>=. CX)              // If Position >= CX (Unsigned compare)
  37.   {
  38.    S1[BX] = 0;               // Clear byte
  39.   }
  40.   BX++;                      // Increment BX
  41.  }
  42.  if(Dest[0] == 0) Dest == StringHeapStartAddress + 2; // NULL string
  43.  return Dest;
  44. }
  45.  
  46.  
  47.  
  48. string RightString(BX_String, CX_Length)
  49. {
  50.  // Returns the Right CX characters of BX_String
  51.  string Dest;
  52.  
  53.  PUSH CX;                    // Save CX for later
  54.  Dest = BX;                  // Copy to new string
  55.  BX = StringLength(Dest);    // Get the string length
  56.  POP CX;                     // Restore CX again
  57.  if(CX > BX) CX = BX;        // Limit size of CX
  58.  CX = Dest + BX - CX;        // Pointer to Address of start of new string
  59.  BX = Dest;                  // Point to start of Dest
  60.  while(S1[BX])               // while not end of string
  61.  {
  62.   if(BX .<. CX)              // If Position < CX (Unsigned compare)
  63.   {
  64.    S1[BX] = 0;               // Clear byte
  65.    Dest++;                   // Move string pointer forward 
  66.   }
  67.   BX++;                      // Increment BX
  68.  }
  69.  if(Dest[0] == 0) Dest == StringHeapStartAddress + 2; // NULL string
  70.  return Dest;
  71. }
  72.  
  73.  
  74. string LeftString(BX_String, CX_Length)
  75. {
  76.  // Returns the Left CX characters of BX_String
  77.  string Dest;
  78.  
  79.  PUSH CX; Dest = BX; POP CX; // Copy to new string
  80.  BX = Dest;                  // Point to start of Dest
  81.  CX = CX + BX;               // Point to character from where to start deleting
  82.  while(S1[BX])               // while not end of string
  83.  {
  84.   if(BX .>=. CX) S1[BX] = 0; // if Position >= CX then clear it (Unsigned compare)
  85.   BX++;                      // Increment BX
  86.  }
  87.  if(Dest[0] == 0) Dest == StringHeapStartAddress + 2; // NULL string
  88.  return Dest;
  89. }
  90.  
  91.  
  92. string CopyString(CX_SourceString)
  93. {
  94.  // Copy a String.  
  95.  // This is called by the compiler when you have the expression :-
  96.  //    String1 = String2;
  97.  // so leave it to the compiler
  98.  string DestString;
  99.  string SourceString;
  100.  unsigned int Segment; // Initialised from Start()
  101.  preserve BX, DX, SI, BP, ES;
  102.  
  103.  SourceString == CX_SourceString;
  104.  SI_DestString = AX;              
  105.  ES = Segment;
  106.  AX = SS;                           // Used in if below
  107.  if(SI == SourceString && Segment == AX)
  108.  {
  109.   // If a string is copied from an address to the same address, then
  110.   // change the destination address to the NULL string, so that the 
  111.   // string does not delete itself
  112.   SI_DestString = StringHeapStartAddress + 2;
  113.   DestString == SI;  
  114.  }
  115.  CX = 0; BX = SourceString;         // Put the Source String
  116.  while(E1[BX] != 0) { BX++; CX++; } // CX = length of Source String
  117.  // Check that destination is between heap limits
  118.  if(SI .<. StringHeapStartAddress || SI .>. StringHeapLastAddress)
  119.  {
  120.   // If the destination string is outside the string heap then make
  121.   // the destination string the NULL string.  NB. this should never 
  122.   // be neccessary but is included just in case someone writes a badly 
  123.   // behaved program.  You may want to call End(203) instead.
  124.   // End(203);
  125.   DestString == StringHeapStartAddress + 2;  // Address of NULL string
  126.  }
  127.  while(S1[SI] != 0) { S1[SI] = 0; SI++; } // Clear the existing data
  128.  if(CX == 0) { DestString == StringHeapStartAddress + 2; return DestString; } // Return NULL string
  129.  while(S1[SI+1] == 0) SI++;         // Search for start of next string
  130.  BP = DestString;                   // BP points to the start of the Destination String
  131.  BX = SI - BP;                      // Available bytes
  132.  if(BX < CX)                        // If not enough room
  133.  {                                  // Try moving backwards
  134.   while(!S1[BP-2] && !S1[BP-3]) BP--; // Search for end of last string
  135.   BX = SI - BP;                     // Available bytes
  136.   if(BX >= CX)                      // If enough room 
  137.   {
  138.    BP = SI - CX;                    // Only take as much room as is needed
  139.    DestString == BP;                // Update the Dest Address
  140.   }
  141.   else
  142.   {                   
  143.    // Store at the end of the Heap
  144.    DestString = RelocateString(CX);
  145.    BP = DestString;
  146.   }
  147.  }
  148.  // Copy the String in
  149.  SI = SourceString;
  150.  while(E1[SI] != 0) { S1[BP] = E1[SI]; SI++; BP++; } 
  151.  return DestString;            // Return Destination String Address
  152. }
  153.  
  154.  
  155.  
  156.  
  157. string AppendString(CX_CatString)
  158. {
  159.  // Append a String.  
  160.  // This is called by the compiler when you have the expression :-
  161.  //    String1 = String1 + String2;
  162.  // so leave it to the compiler
  163.  string DestString;
  164.  string CatString;
  165.  preserve BX, DX, SI, BP;
  166.  
  167.  CatString == CX_CatString;
  168.  BP = AX;
  169.  CX = StringLength(CX_CatString); // Get the Source String Length
  170.  // Check that between heap limits before appending string
  171.  if(BP .<. StringHeapStartAddress || BP .>. StringHeapLastAddress)
  172.  {
  173.   // The Destination String is not in the string heap so copy it into the heap 
  174.   // before appending.  This should not ever occur but is here just in case.
  175.   //cerr << "Not in String Heap\n";
  176.   //cerr << "BP = " << BP << "\n";
  177.   //cerr << "Start = " << StringHeapStartAddress << "\n";
  178.   SI = DestString;
  179.   BP = StringNextFreeAddress;
  180.   while(S1[BP-2] == 0) BP--;    // Move back as far as possible
  181.   DestString == BP;             // Update the Destination address
  182.   while(S1[SI] != 0)            // For each Dest character
  183.   {
  184.    S1[BP] = S1[SI]; // Copy it to the end of the Heap
  185.    SI++; BP++;
  186.   }
  187.   BX = BP + CX; // Address of Terminate Character
  188.   S1[BX] = 0; // Terminate character for concatenated string
  189.   BX++; StringNextFreeAddress = BX; // New End of Heap Pointer
  190.   S1[BX] = '#'; // End of String Heap marker
  191.  }
  192.  else
  193.  {
  194.   // Destination is in the String Heap
  195.   while(S1[BP] != 0) BP++;  // Search for the end of the string 
  196.   BX = BP;                  // BX = End of Dest String pointer
  197.   while(S1[BP] == 0) BP++;  // Search for the start of the next string
  198.   BP--;                     // Last available address
  199.   BX = BP - BX;             // BX = number of spare bytes at end of Dest string
  200.   if(BX >= CX)              // If enough room at end of Dest String
  201.   {                         // to Concatenate other String
  202.    BP = BP - BX;            // Point to end of Dest String before Concatenating
  203.   }
  204.   else
  205.   {
  206.    // There isn't enough room at the end so see if there would be enough room
  207.    // if the String was first moved backwards
  208.    SI = DestString;         // Destination pointer
  209.    while(!S1[SI-2] && !S1[BP-3]) { SI--; BX++; }  // Search for end of last string
  210.    if(BX >= CX)             // If number of Spare Bytes >= Number required
  211.    {
  212.     // Move the String Backwards so that there is more room at the end
  213.     BP = DestString;
  214.     DestString == SI;       // Update the Destination Address
  215.     while(S1[BP] != 0) { S1[SI] = S1[BP]; S1[BP] = 0; SI++; BP++; } // Move String back
  216.     BP = SI;                // BP points to the end of the Dest string
  217.    }
  218.    else
  219.    {
  220.     // Move the Dest String to the end of the Heap
  221.     BP = StringLength(DestString);
  222.     DestString = RelocateString(BP+CX); 
  223.     BP = BP + DestString;
  224.    }
  225.   }
  226.  }
  227.  
  228.  // Concatenate the other String
  229.  SI = CatString; // Point to Source String
  230.  while(S1[SI] != 0) { S1[BP] = S1[SI]; SI++; BP++; }
  231.  if(DestString[0] == 0) DestString == StringHeapStartAddress + 2; // NULL String
  232.  return DestString;
  233. }
  234.  
  235.  
  236. int CompareString(AX, CX)
  237. {
  238.  // Compare two strings
  239.  // This is called by the compiler when you have the expression :-
  240.  // if(String1 == String2) ... etc
  241.  // so leave it to the compiler
  242.  
  243.  // Returns -1, 0, or 1 if Greater than, Equal or Less Than respectively
  244.  preserve SI, BP;
  245.  
  246.  BP = AX;
  247.  SI = CX;
  248.  while(S1[SI] == S1[BP] && S1[SI] != 0) { SI++; BP++; } // Search for Mismatch
  249.  if(S1[SI] == 0 && S1[BP] == 0) return 0; // Strings are equal
  250.  if(S1[BP] > S1[SI]) return  1;           // String1 > String 2
  251.  if(S1[BP] < S1[SI]) return -1;           // String1 < String 2
  252. }
  253.  
  254.  
  255. int CompareNCharactersOfString(AX_String1, BX_String2, CX_Length)
  256. {
  257.  // Compare first few characters of two strings
  258.  // Returns -1, 0, or 1 if Greater than, Equal or Less Than respectively
  259.  preserve SI, BP;
  260.  
  261.  BP = AX_String1;
  262.  SI = BX_String2;
  263.  while(CX>0) 
  264.  {
  265.   if(S1[BP] > S1[SI]) return  1;
  266.   if(S1[BP] < S1[SI]) return -1;
  267.   if(S1[BP] == 0 && S1[SI] == 0) return 0;
  268.   SI++;
  269.   BP++;
  270.   CX--;
  271.  }
  272.  return 0;
  273. }
  274.  
  275.  
  276.  
  277. int StringLength(BX)
  278. {
  279.  // Returns the String Length
  280.  AX = 0;
  281.  while(S1[BX] != 0) { BX++; AX++; }
  282.  return AX;
  283.  
  284.  
  285.  
  286. string StringUpperCase(BX)
  287. {
  288.  // Converts a string to Upper Case
  289.  string DestString;
  290.   
  291.  // Note that at the start of a String Function the return String in the String
  292.  // Function is set to the Destination String of the Calling Function.  So if
  293.  // this Function was called with "NewString = StringUpperCase(OldString);" then
  294.  // DestString is now pointing to NewString, and BX is pointing to OldString.
  295.  
  296.  // Copy the String to DestString if the Destination Address is different to the Source
  297.  if(DestString != BX) DestString = BX;
  298.  
  299.  BX = DestString; // Let BX point to start of DestString
  300.  while(S1[BX] != 0) 
  301.  {
  302.   if(S1[BX] >= 'a' && S1[BX] <= 'z') S1[BX] = S1[BX] - 32;
  303.   BX++;
  304.  }
  305.  return DestString;
  306. }
  307.  
  308.  
  309.  
  310. string StringLowerCase(BX)
  311. {
  312.  // Converts a string to Lower Case
  313.  string DestString;
  314.  
  315.  // Copy the String to DestString if the Destination Address is different to the Source
  316.  if(DestString != BX) DestString = BX;
  317.  
  318.  BX = DestString; // Let BX point to start of DestString
  319.  while(S1[BX] != 0) 
  320.  {
  321.   if(S1[BX] >= 'A' && S1[BX] <= 'Z') S1[BX] = S1[BX] + 32;
  322.   BX++;
  323.  }
  324.  return DestString;
  325. }
  326.  
  327.  
  328.  
  329. string SearchAndReplaceString(AX_String, BX_SearchString, CX_ReplaceString)
  330. {
  331.  // Search one string for another string and replace it with another string
  332.  string String, SearchString, ReplaceString;  
  333.  byte Match;
  334.  byte FoundAMatch;   // Use this by calling program to detect if Match Found
  335.  int  MatchPosition; // Use this by calling program to point to last Match
  336.  int StringLen;
  337.  int SearchStringLength;
  338.  int ReplaceStringLength;
  339.  int Offset;
  340.  preserve SI, BP, DX;
  341.    
  342.  SearchString == BX;
  343.  ReplaceString == CX;
  344.  BP = String;
  345.  DL_FirstChar = S1[BX];
  346.  FoundAMatch = FALSE;
  347.  MatchPosition = -1;
  348.  while(S1[BP] != 0)
  349.  {
  350.   // Search for a match
  351.   if(S1[BP] == DL_FirstChar)
  352.   {
  353.    Match = TRUE;
  354.    PUSH BP;
  355.    SI = 0;
  356.    AL = SearchString[SI];
  357.    while(AL)
  358.    {
  359.     if(S1[BP] != AL) { Match = FALSE; break; }
  360.     SI++; BP++;
  361.     AL = SearchString[SI];
  362.    }
  363.    POP BP;
  364.  
  365.    if(Match)
  366.    {
  367.     FoundAMatch = TRUE;
  368.     MatchPosition = BP - String;
  369.     StringLen = StringLength(String);
  370.     SearchStringLength = StringLength(SearchString);
  371.     ReplaceStringLength = StringLength(ReplaceString);
  372.  
  373.     // If new string will be shorter then shuffle right hand side characters to the left
  374.     if(SearchStringLength > ReplaceStringLength)
  375.     {
  376.      Offset = SearchStringLength - ReplaceStringLength;
  377.      SI = BP + SearchStringLength;
  378.      PUSH BP;
  379.      BP = SI - Offset;
  380.      while(S1[SI] != 0) S1[BP++] = S1[SI++];
  381.      while(S1[BP]) S1[BP++] = 0;
  382.      POP BP;  // Point back to Start of Match
  383.      StringLen = StringLen - Offset;
  384.      if(StringLen == 0) { String == StringHeapStartAddress + 2; return String; }
  385.     }
  386.     // If new string will be longer then shuffle right hand side characters to the right
  387.     if(SearchStringLength < ReplaceStringLength)
  388.     {
  389.      Offset = ReplaceStringLength - SearchStringLength;
  390.      // See if the string needs to be relocated
  391.      for(SI=StringLen+Offset; SI >= StringLen; SI--)
  392.      {
  393.       if(String[SI]) 
  394.       {
  395.        BP = BP - String; // Save Pointer Position
  396.        String = RelocateString(StringLen+Offset);
  397.        BP = BP + String; // Restore Pointer Position
  398.        break;
  399.       }
  400.      }
  401.      //SI = StringLen + Offset; String[SI] = 0;
  402.      SI = String + StringLen - 1;
  403.      CX = BP + SearchStringLength;
  404.      PUSH BP;
  405.      BP = SI + Offset;
  406.      while(SI .>=. CX) S1[BP--] = S1[SI--]; // Unsigned compare
  407.      POP BP;  // Point back to Start of Match
  408.      StringLen = StringLen + Offset;
  409.     }
  410.     // Copy the Replace string in
  411.     SI = 0;
  412.     while(SI < ReplaceStringLength) S1[BP++] = ReplaceString[SI++];
  413.     BP--;
  414.     //PrintStringHeap();
  415.    }
  416.   }
  417.   BP++;
  418.  }
  419.  return String;
  420. }      
  421.  
  422.  
  423.  
  424.  
  425.  
  426. string RelocateString(CX_RequiredLength)
  427. {
  428.  // Move a string to a place where there is sufficient space
  429.  // This is used by the other string functions
  430.  unsigned int HoleAddress;
  431.  string ThisString;
  432.  preserve BP;
  433.  
  434.  BX = AX;                        // Address of string to be relocated
  435.  if(BX < StringHeapStartAddress) End(203); // Invalid String Address
  436.  // If there is enough room at the hole left by the last string then
  437.  // store it there
  438.  BP = HoleAddress;           // Address of string hole
  439.  if(BP)                      // If a hole address has been stored
  440.  {
  441.   if(!S1[BP] && !S1[BP-1] && !S1[BP-2]) // The hole is still there
  442.   {
  443.    while(!S1[BP-3]) BP--;    // Move to beginning of Hole
  444.    HoleAddress = BP;         // New the Hole Address
  445.    while(!S1[BP+1] && !S1[BP+2] && !S1[BP+3]) BP++; // Find the end of the Hole
  446.  
  447.    if(BP - HoleAddress > CX) // if enough room
  448.    {   
  449.     //PUSH ALL; PrintChar(1, 'H'); POP ALL;
  450.     BP = HoleAddress;
  451.     HoleAddress = 0;
  452.     if(BX - 2 != StringHeapStartAddress) HoleAddress = BX; // Keep this hole for next time if is is not the NULL string
  453.  
  454.     //if(BP .>. StringFirstAddress)     { cerr << "BP = " << BP << "\n"; End(111); }
  455.     //if(BP .<. StringHeapStartAddress) { cerr << "BP = " << BP << "\n"; End(111); }
  456.     //if(BX .<. StringHeapStartAddress) { cerr << "BX = " << BX << "\n"; End(111); }
  457.  
  458.     PUSH BP_OldHoleAddress;  // Keep return address
  459.     while(S1[BX]) { S1[BP] = S1[BX]; S1[BX] = 0; BP++; BX++; } // Move String
  460.     POP BX_OldHoleAddress;   // Restore return address
  461.     if(!HoleAddress) HoleAddress = BX + CX + 3;
  462.     ThisString == BX;
  463.     return ThisString;
  464.    }
  465.   }
  466.   else HoleAddress = 0;
  467.  }
  468.  //PUSH ALL; PrintChar(1, 'M'); POP ALL;
  469.  
  470.  if(StringNextFreeAddress + CX .>=. StringHeapLastAddress) // If Heap Full
  471.  {
  472.   PUSH CX;                        // Keep the String length
  473.   TidyStringHeap();               // Tidy the String Heap to make room
  474.   POP CX;                         // Restore the String Length
  475.   BX = ThisString;                // BX now equals the relocated ThisString
  476.   if(StringNextFreeAddress + CX .>=. StringHeapLastAddress)
  477.   {
  478.    // Fatal Error, String Heap Full !!!
  479.    // If the String heap is full then we cannot even terminate properly 
  480.    // because that requires the String Heap, so the program terminates here
  481.    cerr << "String Heap Full\n";
  482.    AX = 4CC8h; INT 21h;        // Terminate program with Error Code C8h
  483.   }
  484.  }
  485.  
  486.  if(BX - 2 != StringHeapStartAddress) HoleAddress = BX + 1; // Keep the current address for future strings if not the NULL string
  487.  BP = StringNextFreeAddress; // Set the Address equal to the next free address
  488.  while(!S1[BP-1] && !S1[BP-2] && !S1[BP-3]) BP--; // Move back as far as possible
  489.  PUSH BP;                    // Keep the Destination Address
  490.  while(S1[BX]) { S1[BP] = S1[BX]; S1[BX] = 0; BP++; BX++; } // Move String
  491.  POP AX;                     // Return String Address
  492.  BP = AX + CX;               // Address of Terminate Character
  493.  S1[BP++] = 0;               // Terminate character string
  494.  S1[BP++] = 0;               // Terminate character string
  495.  S1[BP] = '#';               // End of String Heap marker
  496.  StringNextFreeAddress = BP; // New End of Heap Pointer
  497.  ThisString == AX; return ThisString;
  498. }
  499.  
  500.  
  501.  
  502. void ClearTemporaryString(BX)
  503. {
  504.  // Used by compiler to clear Temporary strings
  505.  // Must not alter AX
  506.  while(S1[BX]) S1[BX++] = 0;
  507. }
  508.  
  509.  
  510.  
  511. string PushString(AX)
  512. {
  513.  // PUSH a string onto the string stack
  514.  // This is used by the "preserve" instruction to preserve a string
  515.  string PUSHString;
  516.  string TempString;
  517.  preserve BX, CX;
  518.  
  519.  PUSHString == AX;
  520.  TempString = PUSHString; // Make a Duplicate
  521.  if(StringNextFreeAddress + 4 .>. StringFirstAddress)
  522.  {
  523.   TidyStringHeap();
  524.   if(StringNextFreeAddress + 4 .>. StringFirstAddress) End(202); // String Heap Full
  525.  }
  526.  StringFirstAddress = StringFirstAddress - 2; // Assign new String variable
  527.  S2[0] = StringFirstAddress;                  // Temporary ***
  528.  StringHeapLastAddress = StringHeapLastAddress - 2; // Change String Heap boundary
  529.  BX = StringFirstAddress;
  530.  S2[BX] = PUSHString;
  531.  // PUSHString is now allocated to S2[BX] so deallocate PUSHString
  532.  PUSHString == StringHeapStartAddress + 2;  // Make PUSHString point to NULL String
  533.  return TempString;
  534. }
  535.  
  536.  
  537.  
  538. string PopString()
  539. {
  540.  // POP a string off the string stack
  541.  // This is used by the "preserve" instruction
  542.  // The string is restored to it's origional address so pointers to the 
  543.  // string are still valid
  544.  string POPString;
  545.  preserve BX, CX;
  546.  
  547.  POPString = "";    // Clear the old string
  548.  BX = StringFirstAddress;
  549.  POPString == S2[BX];  // Reassign PUSHed string to this string
  550.  StringFirstAddress = StringFirstAddress + 2; // Remove String variable
  551.  S2[0] = StringFirstAddress;                  // Temporary ***
  552.  StringHeapLastAddress = StringHeapLastAddress + 2; // Change String Heap boundary
  553.  return POPString;
  554. }
  555.  
  556.  
  557. void TidyStringHeap()
  558. {
  559.  // Tidy the string heap so that there are no gaps
  560.  unsigned int StructureSegment[MAXSTRUCTURES];
  561.  byte Found;
  562.  preserve DI,SI,BP,DX,ES;
  563.  
  564.  //cerr << "Tidying String Heap\n";
  565.  //LogFile << "Tidying String Heap\n";
  566.  
  567.  // Check that all the string pointers are valid
  568.  for(DI=0; DI<MAXSTRUCTURES; DI++)
  569.  {
  570.   if(StructureSegment[DI])
  571.   {
  572.    ES = StructureSegment[DI];
  573.    for(SI=E2[0]; SI.<=.E2[2]; SI=SI+2) // for(SI=StringFirstAddress; SI.<=.StringLastAddress; SI=SI+2)
  574.    {
  575.     BP = E2[SI];
  576.     if(BP - 2 != StringHeapStartAddress) // If not the NULL String address
  577.     {
  578.      if(!S1[BP] || S1[BP-1]) // If there is no first character or the pointer points to the middle of a string
  579.      {
  580.       //PrintString(1, E2[SI]); cerr << " is invalid\n";
  581.       //PrintString(LogFile, E2[SI]); LogFile << " at address " << IntegerToHexString(SI) << " is invalid\n";
  582.       E2[SI] = StringHeapStartAddress + 2;
  583.      }
  584.     }
  585.    }
  586.   }
  587.  }
  588.  
  589.  
  590.  // Find the first string
  591.  BP = StringHeapStartAddress + 5;
  592.  while(S2[BP] != 0)
  593.  {
  594.   if(BP .>=. StringNextFreeAddress) return;
  595.   BP++;
  596.  }
  597.  DI = BP + 1;
  598.  while(S1[BP] == 0) BP++;
  599.  
  600.  while(BP.<.StringNextFreeAddress)
  601.  {
  602.   Found = FALSE;
  603.   for(DX=0; DX<MAXSTRUCTURES; DX++)
  604.   {
  605.    if(StructureSegment[DX])
  606.    {
  607.     ES = StructureSegment[DX];
  608.     for(SI=E2[0]; SI.<=.E2[2]; SI=SI+2) // for(SI=StringFirstAddress; SI.<=.StringLastAddress; SI=SI+2)
  609.     {
  610.      if(E2[SI] == BP) 
  611.      {
  612.       //PrintString(1, E2[SI]); cerr << " must move\n";
  613.       E2[SI] = DI;
  614.       Found = TRUE;
  615.      }
  616.     }
  617.    }
  618.   }
  619.   if(Found) while(S1[BP]) { S1[DI] = S1[BP]; S1[BP] = 0; DI++; BP++; }
  620.   else 
  621.   {
  622.    #ifdef DEBUG
  623.    cerr << "Deleting '"; PrintString(1, BP); cerr << "'\n";
  624.    #endif
  625.    //LogFile << "Deleting '"; PrintString(LogFile, BP); LogFile << "'\n";
  626.    while(S1[BP]) S1[BP++] = 0;
  627.    //End(0);
  628.   }
  629.   DI++;
  630.   while(S1[BP] == 0) BP++;
  631.  }
  632.  StringNextFreeAddress = DI;
  633.  S1[DI] = '#';
  634.  
  635.  RelocateString.HoleAddress = 0;
  636. }
  637.  
  638.  
  639. void PrintStringHeap()
  640. {
  641.  // Print the String Heap
  642.  // Used for debugging only
  643.  preserve SI, DX;
  644.  
  645.  SI = StringHeapStartAddress;
  646.  while(SI .<=. StringNextFreeAddress)
  647.  {
  648.   DL = S1[SI];
  649.   if(DL < ' ') DL = '.';
  650.   PutByte(cout, DL);
  651.   SI++;
  652.  }
  653.  PutByte(cout, 13);
  654.  PutByte(cout, 10);
  655. }
  656.  
  657.  
  658.  
  659. void PrintScratchPad()
  660. {
  661.  // Print the ScratchPad
  662.  // Used for debugging only
  663.  preserve ALL;
  664.  
  665.  SI = ScratchPadAddress;
  666.  for(BX=0; BX<320h; BX++)
  667.  {
  668.   DL = S1[BX+SI];
  669.   if(DL < ' ') DL = '.';
  670.   if(DL > 127) DL = '.';
  671.   AH = 2; INT 21h;
  672.  }
  673.  DL = 13; INT 21h;
  674.  DL = 10; INT 21h;
  675. }
  676.  
  677.  
  678. string CharToString(AL)
  679. {
  680.  string CharString;
  681.  
  682.  BX = StringHeapStartAddress;
  683.  S1[BX++] = AL;
  684.  S1[BX] = 0;
  685.  CharString = StringHeapStartAddress;
  686.  return CharString;
  687. }
  688.  
  689.  
  690. string ByteToString(CL)
  691. {
  692.  // Convert a byte to a string
  693.  string RetString;
  694.  
  695.  CH = 0;
  696.  RetString = IntegerToString(CX);
  697.  return RetString;
  698. }
  699.  
  700.  
  701. string IntegerToString(CX)
  702. {
  703.  // Convert an integer to a string
  704.  string RetString;
  705.  byte NegativeNumber;
  706.  preserve DX, DI;
  707.  
  708.  AX = CX;
  709.  DI = ScratchPadAddress + 30;
  710.  S1[DI] = 0;
  711.  CX = 10;
  712.  if(AX == 0) { DI--; S1[DI] = '0'; }
  713.  NegativeNumber = 0;
  714.  if(AX < 0) { AX = - AX; NegativeNumber = 1; }
  715.  while(AX > 0)
  716.  {
  717.   DX = 0;
  718.   AX = DX:AX / CX; // DX = Remainder
  719.   DL = DL + 48;
  720.   DI--;
  721.   S1[DI] = DL;
  722.  }
  723.  if(NegativeNumber) { DI--; S1[DI] = '-'; }
  724.  RetString = DI; // Copy scratchpad into RetString
  725.  return RetString;
  726. }
  727.  
  728.  
  729. string ByteToHexString(CL_Word)
  730. {
  731.  // Convert a byte to a HEX string
  732.  string DestString;
  733.  preserve DX;
  734.  
  735.  DX_Word = CX_Word;
  736.  BX = ScratchPadAddress;
  737.  for(CL=4; CL>=0; CL=CL-4)
  738.  {
  739.   AX = ((DX >> CL) & 0xF) + 48;
  740.   if(AX > 57) AX = AX + 7;
  741.   S1[BX++] = AL; 
  742.  }
  743.  S1[BX++] = 'h';
  744.  S1[BX] = 0;
  745.  DestString = ScratchPadAddress; // Copy string into DestString
  746.  return DestString;
  747. }
  748.  
  749.  
  750. string IntegerToHexString(CX_Word)
  751. {
  752.  // Convert an integer to a HEX string
  753.  string DestString;
  754.  preserve DX;
  755.  
  756.  DX_Word = CX_Word;
  757.  BX = ScratchPadAddress;
  758.  for(CL=12; CL>=0; CL=CL-4)
  759.  {
  760.   AX = ((DX >> CL) & 0xF) + 48;
  761.   if(AX > 57) AX = AX + 7;
  762.   S1[BX++] = AL; 
  763.  }
  764.  S1[BX++] = 'h';
  765.  S1[BX] = 0;
  766.  DestString = ScratchPadAddress; // Copy string into DestString
  767.  return DestString;
  768. }
  769.  
  770.  
  771. string LongIntegerToHexString(ECX_Word)
  772. {
  773.  // Convert a long integer to a HEX string
  774.  string DestString;
  775.  preserve EDX;
  776.  
  777.  EDX_Word = ECX_Word;
  778.  BX = ScratchPadAddress;
  779.  for(CL=28; CL>=0; CL=CL-4)
  780.  {
  781.   EAX = ((EDX >> CL) & 0xF) + 48;
  782.   if(AX > 57) AX = AX + 7;
  783.   S1[BX++] = AL; 
  784.  }
  785.  S1[BX++] = 'h';
  786.  S1[BX] = 0;
  787.  DestString = ScratchPadAddress; // Copy string into DestString
  788.  return DestString;
  789. }
  790.  
  791.  
  792. byte StringToByte(AX_StringAddress)
  793. {
  794.  // Convert a string to a byte
  795.  // The string can be in integer or hex form
  796.  AX = StringToInteger(AX_StringAddress);
  797.  return AL;
  798. }
  799.  
  800.  
  801. int StringToInteger(string String)
  802. {
  803.  // Convert a string to a signed integer
  804.  // The string can be in integer or hex form
  805.  int NumberIsValid;
  806.  int NumberIsNegative;
  807.  preserve DI, SI, DX;
  808.  
  809.  NumberIsValid = FALSE;
  810.  DX = 0;  // This is where the number will be placed
  811.  
  812.  while(String[0] == ' ') String++;  // Skip white space at start
  813.  SI = StringLength(String);
  814.  if(SI == 0) return 0;
  815.  SI--; while(String[SI] == ' ') SI--;  // Skip white space at end
  816.  
  817.  // See if type '?'
  818.  if(String[0] == ''' && String[2] == ''' && SI == 2)
  819.  {
  820.   NumberIsValid = TRUE;
  821.   DL = String[1];
  822.  }
  823.  // See if it is a Hex number ending with an "h"
  824.  else if(String[SI] == 'h')
  825.  {
  826.   for(DI=0; DI<SI; DI++)
  827.   {
  828.    NumberIsValid = TRUE;
  829.    if(String[DI] >= '0' && String[DI] <= '9') AL = String[DI] - 48;
  830.    else if(String[DI] >= 'A' && String[DI] <= 'F') AL = String[DI] - 55;
  831.    else if(String[DI] >= 'a' && String[DI] <= 'f') AL = String[DI] - 87;
  832.    else { NumberIsValid = FALSE; break; }
  833.    AH = 0;
  834.    DX = DX << 4;
  835.    DX = DX + AX;
  836.   } // end for
  837.  } // end if = "h"
  838.  // See if it is a Hex number starting with a "0x"
  839.  else if(String[0] == '0' && (String[1] == 'x' || String[1] == 'X'))  
  840.  {
  841.   for(DI=2; DI<=SI; DI++)
  842.   {
  843.    NumberIsValid = TRUE;
  844.    if(String[DI] >= '0' && String[DI] <= '9') AL = String[DI] - 48;
  845.    else if(String[DI] >= 'A' && String[DI] <= 'F') AL = String[DI] - 55;
  846.    else if(String[DI] >= 'a' && String[DI] <= 'f') AL = String[DI] - 87;
  847.    else { NumberIsValid = FALSE; break; }
  848.    AH = 0;
  849.    DX = DX << 4;
  850.    DX = DX + AX;
  851.   } // end for
  852.  } // end if = "0x"
  853.  else   
  854.  {
  855.   // Assume to be a Decimal number
  856.   NumberIsNegative = FALSE;
  857.   if(String[0] == '-') { NumberIsNegative = TRUE; String++; SI--; }
  858.   for(DI=0; DI<=SI; DI++)
  859.   {
  860.    NumberIsValid = TRUE;
  861.    if(String[DI] >= '0' && String[DI] <= '9')
  862.    {
  863.     AL = String[DI] - 48;
  864.     AH = 0;
  865.     DX = DX * 10;
  866.     DX = DX + AX;
  867.    }
  868.    else { NumberIsValid = FALSE; break; }
  869.   } // end for
  870.   if(NumberIsNegative) DX = -DX;
  871.  } // end if = Decimal Number
  872.  return DX;
  873. }
  874.  
  875.  
  876.  
  877. long StringToLongInteger(string String)
  878. {
  879.  // Convert a string to a signed long integer
  880.  // The string can be in integer or hex form
  881.  byte NumberIsValid;
  882.  int NumberIsNegative;
  883.  preserve DI, SI, EDX;
  884.  
  885.  NumberIsValid = FALSE;
  886.  EDX = 0;  // This is where the number will be placed
  887.  
  888.  while(String[0] == ' ') String++;  // Skip white space at start
  889.  SI = StringLength(String);
  890.  if(SI == 0) return 0;
  891.  SI--; while(String[SI] == ' ') SI--;  // Skip white space at end
  892.  
  893.  // See if type '?'
  894.  if(String[0] == ''' && String[2] == ''' && SI == 2)
  895.  {
  896.   NumberIsValid = TRUE;
  897.   DL = String[1];
  898.  }
  899.  // See if it is a Hex number ending with an "h"
  900.  else if(String[SI] == 'h')
  901.  {
  902.   for(DI=0; DI<SI; DI++)
  903.   {
  904.    NumberIsValid = TRUE;
  905.    EAX = 0;
  906.    if(String[DI] >= '0' && String[DI] <= '9') AL = String[DI] - 48;
  907.    else if(String[DI] >= 'A' && String[DI] <= 'F') AL = String[DI] - 55;
  908.    else if(String[DI] >= 'a' && String[DI] <= 'f') AL = String[DI] - 87;
  909.    else { NumberIsValid = FALSE; break; }
  910.    EDX = EDX << 4;
  911.    EDX = EDX + EAX;
  912.   } // end for
  913.  } // end if = "h"
  914.  
  915.  // See if it is a Hex number starting with a "0x"
  916.  else if(String[0] == '0' && (String[1] == 'x' || String[1] == 'X'))  
  917.  {
  918.   for(DI=2; DI<=SI; DI++)
  919.   {
  920.    NumberIsValid = TRUE;
  921.    EAX = 0;
  922.    if(String[DI] >= '0' && String[DI] <= '9') AL = String[DI] - 48;
  923.    else if(String[DI] >= 'A' && String[DI] <= 'F') AL = String[DI] - 55;
  924.    else if(String[DI] >= 'a' && String[DI] <= 'f') AL = String[DI] - 87;
  925.    else { NumberIsValid = FALSE; break; }
  926.    EDX = EDX << 4;
  927.    EDX = EDX + EAX;
  928.   } // end for
  929.  } // end if = "0x"
  930.  else   
  931.  {
  932.   // Assume to be a Decimal number
  933.   NumberIsNegative = FALSE;
  934.   if(String[0] == '-') { NumberIsNegative = TRUE; String++; SI--; }
  935.   for(DI=0; DI<=SI; DI++)
  936.   {
  937.    NumberIsValid = TRUE;
  938.    if(String[DI] >= '0' && String[DI] <= '9')
  939.    {
  940.     EAX = 0;
  941.     AL = String[DI] - 48;
  942.     EDX = EDX * 10;
  943.     EDX = EDX + EAX;
  944.    }
  945.    else { NumberIsValid = FALSE; break; }
  946.   } // end for
  947.   if(NumberIsNegative) EDX = -EDX;
  948.  } // end if = Decimal Number
  949.  return EDX;
  950. }
  951.  
  952.  
  953.  
  954.